﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using Application = System.Windows.Application;
using MouseEventArgs = System.Windows.Forms.MouseEventArgs;

namespace MishraReader.Interop
{
    [ContentProperty("Text")]
    [DefaultEvent("MouseDoubleClick")]
    public class NotificationIcon : FrameworkElement
    {
        public event EventHandler BalloonClick
        {
            add { AddHandler(BalloonClickEvent, value); }
            remove { RemoveHandler(BalloonClickEvent, value); }
        }

        public event MouseButtonEventHandler MouseClick
        {
            add { AddHandler(MouseClickEvent, value); }
            remove { RemoveHandler(MouseClickEvent, value); }
        }

        public event MouseButtonEventHandler MouseDoubleClick
        {
            add { AddHandler(MouseDoubleClickEvent, value); }
            remove { RemoveHandler(MouseDoubleClickEvent, value); }
        }

        public static readonly RoutedEvent BalloonClickEvent = EventManager.RegisterRoutedEvent("BalloonClick", RoutingStrategy.Bubble,
                                                                                                typeof(RoutedEventHandler), typeof(NotificationIcon));

        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(NotificationIcon));

        public static readonly RoutedEvent MouseClickEvent = EventManager.RegisterRoutedEvent("MouseClick", RoutingStrategy.Bubble,
                                                                                              typeof(MouseButtonEventHandler), typeof(NotificationIcon));

        public static readonly RoutedEvent MouseDoubleClickEvent = EventManager.RegisterRoutedEvent("MouseDoubleClick", RoutingStrategy.Bubble,
                                                                                                    typeof(MouseButtonEventHandler), typeof(NotificationIcon));

        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(NotificationIcon));

        private bool initialized;
        private NotifyIcon notifyIcon;

        public ImageSource Icon
        {
            get { return (ImageSource) GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        public string Text
        {
            get { return (string) GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public void ShowBallon(string text)
        {
            notifyIcon.ShowBalloonTip((int) TimeSpan.FromMinutes(1).TotalMilliseconds, Strings.Notification, text, ToolTipIcon.Info);
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            InitializeNotifyIcon();
            Dispatcher.ShutdownStarted += OnDispatcherShutdownStarted;
        }

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);

            if (initialized)
            {
                switch (e.Property.Name)
                {
                    case "Icon":
                        notifyIcon.Icon = FromImageSource(Icon);
                        break;
                    case "Text":
                        notifyIcon.Text = Text;
                        break;
                    case "Visibility":
                        notifyIcon.Visible = FromVisibility(Visibility);
                        break;
                }
            }
        }

        internal void UpdateVisibility(bool value)
        {
            notifyIcon.Visible = value;
        }

        private bool FromVisibility(Visibility visibility)
        {
            return visibility == Visibility.Visible /*&& _optionsManager.UseNotificationIcon*/;
        }

        private void InitializeNotifyIcon()
        {
            notifyIcon = new NotifyIcon {Text = Text, Icon = FromImageSource(Icon), Visible = FromVisibility(Visibility)};

            notifyIcon.MouseDown += OnMouseDown;
            notifyIcon.MouseUp += OnMouseUp;
            notifyIcon.MouseClick += OnMouseClick;
            notifyIcon.MouseDoubleClick += OnMouseDoubleClick;
            notifyIcon.BalloonTipClicked += notifyIcon_BalloonTipClicked;

            initialized = true;
        }

        private void OnRaiseEvent(RoutedEvent handler, MouseButtonEventArgs e)
        {
            e.RoutedEvent = handler;
            RaiseEvent(e);
        }

        private void ShowContextMenu()
        {
            if (ContextMenu == null)
                return;
            ContextMenuService.SetPlacement(ContextMenu, PlacementMode.MousePoint);
            ContextMenu.IsOpen = true;
        }

        private void OnDispatcherShutdownStarted(object sender, EventArgs e)
        {
            notifyIcon.Dispose();
        }

        private void OnMouseClick(object sender, MouseEventArgs e)
        {
            OnRaiseEvent(MouseClickEvent, new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button)));
        }

        private void OnMouseDoubleClick(object sender, MouseEventArgs e)
        {
            OnRaiseEvent(MouseDoubleClickEvent, new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button)));
        }

        private void OnMouseDown(object sender, MouseEventArgs e)
        {
            OnRaiseEvent(MouseDownEvent, new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button)));
        }

        private void OnMouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ShowContextMenu();
            }
            OnRaiseEvent(MouseUpEvent, new MouseButtonEventArgs(InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button)));
        }

        private void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(BalloonClickEvent));
        }

        private static Icon FromImageSource(ImageSource icon)
        {
            if (icon == null)
            {
                return null;
            }
            var iconUri = new Uri(icon.ToString());
            return new Icon(Application.GetResourceStream(iconUri).Stream);
        }

        private static MouseButton ToMouseButton(MouseButtons button)
        {
            switch (button)
            {
                case MouseButtons.Left:
                    return MouseButton.Left;
                case MouseButtons.Right:
                    return MouseButton.Right;
                case MouseButtons.Middle:
                    return MouseButton.Middle;
                case MouseButtons.XButton1:
                    return MouseButton.XButton1;
                case MouseButtons.XButton2:
                    return MouseButton.XButton2;
            }
            throw new InvalidOperationException();
        }
    }
}